from django import forms
from web import models
from django.core.validators import RegexValidator  # 正则表达式
from django.conf import settings  # 默认配置
import random  # 随机数
from utils.tencent.sms import send_sms_single  # 发送短信模块
from django_redis import get_redis_connection  # 操作redis模块
from utils import encrypt
from .bootstrap import BootstrapForm


# 生成页面标签
class RegisterModelFOrm(BootstrapForm, forms.ModelForm):
    phone = forms.CharField(label='手机号',
                            validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机格式错误')])  # 重写数据库字段 加入正则表达式
    password = forms.CharField(label='密码', min_length=8, max_length=64,
                               error_messages={'min_length': '密码太短不能小于8个字符', 'max_length': '密码太长了'},
                               widget=forms.PasswordInput())  # 将密码改写成为密文
    passwords = forms.CharField(label='确认密码', min_length=8, max_length=64,
                                error_messages={'min_length': '密码太短不能小于8个字符', 'max_length': '密码太长了'},
                                widget=forms.PasswordInput())  # 将密码改写成为密文attrs用来给生成的标签添加属性
    code = forms.CharField(label='验证码')

    class Meta:
        model = models.UserInfo
        fields = ['username', 'email', 'password', 'passwords', 'phone', 'code']

    # 定义用户名的钩子函数
    def clean_username(self):
        # 获取用户名
        username = self.cleaned_data['username']
        # 用户名校验
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            # raise ValueError('用户名重复')
            self.add_error('username', '用户名已存在')
        return username

    # 密码加密
    def clean_password(self):
        password = self.cleaned_data['password']
        return encrypt.md5(password)

    # 验证两次密码是否相等
    # 获取值时,只能获取在它顺序之前的值,因为后面的值还没有校验
    def clean_passwords(self):
        pwd = self.cleaned_data.get('password')
        pwds = encrypt.md5(self.cleaned_data['passwords'])
        if pwd != pwds:
            # raise ValueError('两次密码不一致')
            self.add_error('passwords', '两次密码不一致')
        return pwds

    # 手机号校验
    def clean_phone(self):
        phone = self.cleaned_data['phone']
        exists = models.UserInfo.objects.filter(phone=phone).exists()
        if exists:
            # raise ValueError('手机号已存在')
            self.add_error('phone', '手机号已存在')
        return phone

    # 验证码校验
    def clean_code(self):
        code = self.cleaned_data['code']
        phone = self.cleaned_data['phone']
        conn = get_redis_connection('default')
        redis_code = conn.get(phone)
        if not redis_code:
            # raise ValueError('验证码时效或为发送,请重新发送')
            self.add_error('code', '验证码时效或为发送,请重新发送')
            return

        str_code = redis_code.decode('utf-8')  # 类型转化

        if code.strip() != str_code:
            # raise ValueError('验证输入错误')
            self.add_error('code', '验证码输入有误')

        return code


# 进行验证处理
class SendSmsForm(forms.Form):
    phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机格式错误')])

    def __init__(self, request, *args, **kwargs):
        super(SendSmsForm, self).__init__(*args, **kwargs)
        self.request = request

    def clean_phone(self):
        # 定义一个钩子方法
        # self.cleaned_data['phone']用户提交过来的参数
        tpl = self.request.GET.get('tpl')
        temp_id = settings.TENCENT_SMS_TEMPLATE[tpl]
        phone = self.cleaned_data['phone']
        exists = models.UserInfo.objects.filter(phone=phone).exists()

        if not temp_id:
            raise ValueError('参数不存在')

        if tpl == 'login':
            if not exists:
                # raise ValueError('手机号不存在')
                self.add_error('phone', '手机号不存在')
                return
        else:
            if exists:
                # raise ValueError('手机号已存在')
                self.add_error('phone', '手机号已存在')
                return
        # 发送短信
        code = random.randrange(1000, 9999)
        sms = send_sms_single(phone, temp_id, [code, ])
        if sms['result'] != 0:
            raise ValueError('短信发送失败,{}'.format(sms['errmsg']))

        # 验证码写入redis中
        conn = get_redis_connection('default')
        conn.set(phone, code, ex=60)  # 手机号,验证码,超时时间

        return phone


# 使用Form就需要自己写字段
class LoginSMSForm(BootstrapForm, forms.Form):
    phone = forms.CharField(label='手机号',
                            validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机格式错误')])  # 重写数据库字段 加入正则表达式
    code = forms.CharField(label='验证码')

    def clean_phone(self):
        phone = self.cleaned_data['phone']
        user_object = models.UserInfo.objects.filter(phone=phone).first()
        if not user_object:
            self.add_error('phone', '手机号不存在')
            return
        return user_object

    def clean_code(self):
        code = self.cleaned_data['code']
        user_object = self.cleaned_data['phone']
        if not user_object:
            return code

        coon = get_redis_connection('default')
        redis_code = coon.get(user_object.phone)
        str_code = redis_code.decode('utf-8')
        if code.strip() != str_code:
            self.add_error('code', '验证码输入错误')

        return code


# 使用用户名登录
class LoginForm(BootstrapForm, forms.Form):
    username = forms.CharField(label='用户名或邮箱登录')
    password = forms.CharField(label='密码', widget=forms.PasswordInput(render_value=True))  # render_value=True刷新不丢失
    code = forms.CharField(label='图片验证码')

    def __init__(self, request, *args, **kwargs):
        super(LoginForm, self).__init__(*args, **kwargs)
        self.request = request

    # 密码加密
    def clean_password(self):
        pwd = self.cleaned_data['password']
        return encrypt.md5(pwd)

    # 验证码校验
    def clean_code(self):
        """钩子判断图片是否正确"""
        # 读取用户输入验证码
        code = self.cleaned_data['code']
        session_code = self.request.session.get('image_code')
        if not session_code:
            self.add_error('code', '验证码过期')
            return
        if code.upper() != session_code.upper():
            self.add_error('code', '验证码输入错误')
            return
        return code
